import { useCallback, useContext, useEffect, useMemo } from 'react'
import { useNavigate } from 'react-router-dom'
import { Flex, Img, Input, Spinner } from 'honorable'
import { Button, FormField, ListBoxItem, Select } from '@pluralsh/design-system'

import { OnboardingContext } from '../../context/onboarding'
import { ScmProvider } from '../../../../../generated/graphql'
import { isAlphanumeric } from '../../../helpers'
import {
  ConfigureCloudSectionState,
  OrgType,
  SCMOrg,
} from '../../context/types'
import { useSectionState } from '../../context/hooks'
import useOnboarded from '../../../hooks/useOnboarded'

import { useGithubState } from './provider/github'
import { useGitlabState } from './provider/gitlab'
import { useRepoExists } from './provider/useRepoExists'

interface OrgInputProps {
  orgs: Array<SCMOrg>
}

function providerToOrgLabel(provider?: ScmProvider): string {
  switch (provider) {
    case ScmProvider.Gitlab:
      return 'GitLab group'
    case ScmProvider.Github:
      return 'GitHub organization'
  }

  return 'Organization or group'
}

function OrgInput({ orgs }: OrgInputProps) {
  const {
    scm: { provider, org },
    setSCM,
  } = useContext(OnboardingContext)
  const setOrg = useCallback(
    (org) => setSCM((scm) => ({ ...scm, org })),
    [setSCM]
  )
  const setOrgByKey = useCallback(
    (id) => {
      const org = orgs.find((o) => o.id === id)

      setSCM((scm) => ({ ...scm, org }))
    },
    [orgs, setSCM]
  )

  useEffect(() => {
    if (org) return

    const userOrg = orgs.find((o) => o.orgType === OrgType.User)

    if (!userOrg) return

    setOrg(userOrg)
  }, [org, orgs, setOrg])

  return (
    <FormField
      width="100%"
      label={providerToOrgLabel(provider)}
    >
      <Select
        onSelectionChange={(key) => setOrgByKey(key)}
        selectedKey={org?.id}
        leftContent={
          org?.avatarUrl && (
            <Img
              borderRadius="medium"
              src={org?.avatarUrl}
              width={24}
              height={24}
            />
          )
        }
      >
        {orgs?.map((o) => (
          <ListBoxItem
            key={o.id}
            label={o.name}
            textValue={o.name}
            leftContent={
              <Img
                borderRadius="medium"
                marginRight="xsmall"
                src={o.avatarUrl}
                display="block"
                width={24}
                height={24}
              />
            }
          />
        ))}
      </Select>
    </FormField>
  )
}

function RepositoryInput({ orgs, provider }: any) {
  const { scm, setSCM, setValid } = useContext(OnboardingContext)
  const maxLen = 100
  const setName = useCallback(
    (name: string) => setSCM({ ...scm, repositoryName: name }),
    [setSCM, scm]
  )
  const { loading, exists, validated } = useRepoExists(
    scm.token,
    scm.org,
    scm.repositoryName,
    provider
  )
  const isValid = useMemo(
    () =>
      !!scm?.repositoryName?.length &&
      isAlphanumeric(scm?.repositoryName) &&
      !exists &&
      validated,
    [scm?.repositoryName, exists, validated]
  )

  useEffect(() => setValid(isValid), [isValid, setValid])

  return (
    <>
      <OrgInput orgs={orgs} />
      <FormField
        width="100%"
        marginTop="medium"
        label="Repository name"
        hint={
          exists
            ? 'This repository already exists. Please use a different name.'
            : "Your repository's name must be globally unique."
        }
        length={scm?.repositoryName?.length || 0}
        maxLength={maxLen}
        error={!isValid}
      >
        <Input
          error={!isValid}
          width="100%"
          onChange={({ target: { value } }) =>
            setName(value.substring(0, maxLen))
          }
          value={scm?.repositoryName}
          placeholder="Choose a repository name"
          endIcon={loading ? <Spinner /> : null}
        />
      </FormField>
    </>
  )
}

function GithubRepositoryInput() {
  const { scm } = useContext(OnboardingContext)
  const orgs = useGithubState({ token: scm.token })

  return (
    <RepositoryInput
      orgs={orgs}
      provider={ScmProvider.Github}
    />
  )
}

function GitlabRepositoryInput() {
  const { scm } = useContext(OnboardingContext)
  const orgs = useGitlabState({ token: scm.token })

  return (
    <RepositoryInput
      orgs={orgs}
      provider={ScmProvider.Gitlab}
    />
  )
}

export function ProviderInput() {
  const {
    scm: { provider: scmProvider },
  } = useContext(OnboardingContext)

  if (scmProvider === ScmProvider.Github) {
    return <GithubRepositoryInput />
  }
  if (scmProvider === ScmProvider.Gitlab) {
    return <GitlabRepositoryInput />
  }

  return null
}

export function ProviderConfiguration() {
  const context = useContext(OnboardingContext)
  const {
    scm: { provider: scmProvider },
    valid,
  } = context
  const setSectionState = useSectionState()
  const navigate = useNavigate()
  const { fresh: isOnboarding, mutation } = useOnboarded()

  const onBack = useCallback(
    () => setSectionState(ConfigureCloudSectionState.RepositorySelection),
    [setSectionState]
  )

  return (
    <div>
      <ProviderInput />
      <Flex
        gap="medium"
        justify={isOnboarding ? 'space-between' : 'flex-end'}
        borderTop="1px solid border"
        marginTop="xlarge"
        paddingTop="large"
      >
        {isOnboarding && (
          <Button
            data-phid="skip-onboarding"
            secondary
            onClick={() => {
              mutation()
              navigate('/overview/clusters')
            }}
          >
            Skip onboarding
          </Button>
        )}
        <Flex
          grow={isOnboarding ? 0 : 1}
          gap="medium"
          justify="space-between"
        >
          <Button
            data-phid={`back-from-repo-config${
              scmProvider ? `-${scmProvider.toLowerCase()}` : ''
            }`}
            secondary
            onClick={() => onBack()}
          >
            Back
          </Button>
          <Button
            data-phid={`cont-from-repo-config${
              scmProvider ? `-${scmProvider.toLowerCase()}` : ''
            }`}
            disabled={!valid}
            onClick={() =>
              setSectionState(ConfigureCloudSectionState.CloudConfiguration)
            }
          >
            Continue
          </Button>
        </Flex>
      </Flex>
    </div>
  )
}
